#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>

#import "view.h"

#include "render.h"
#include "system.h"
#include "log.h"

typedef struct _POINT {
    ufoPoint pt;
    void *id;
}POINT;

POINT g_touch_point[10];

int internal_route_sizeChanged(void* wParam, void* lParam);
int internal_route_ncHitTest(void* wParam, void* lParam);
int internal_route_touchEvent(int msg, void* wParam, void* lParam);

#define USE_DEPTH_BUFFER	1

@implementation ufoView

+ (Class)layerClass {
    return [CAEAGLLayer class];
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        
        // Get the layer
        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
        
        eaglLayer.opaque = NO;
        eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                        [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
        
        context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
        
        if (!context || ![EAGLContext setCurrentContext:context]) {
            [self release];
            return nil;
        }
        
        CADisplayLink *aDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(myDrawFrame)];
        [aDisplayLink setFrameInterval:1/60.0f];
        [aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        displayLink = aDisplayLink;
		
		[self registerForKeyboardNotifications];
        
        [self setMultipleTouchEnabled:YES];
    }
    return self;
}

//The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
- (id)initWithCoder:(NSCoder*)coder {
    if ((self = [super initWithCoder:coder])) {
        
    }
    return self;
}

void addTouchPoint(float x, float y, void *id) {
    for (int i = 0; i < 10; ++i) {
        if (!g_touch_point[i].id) {
            g_touch_point[i].pt.x = x;
            g_touch_point[i].pt.y = y;
            g_touch_point[i].id = id;
            break;
        }
    }
}

void removeTouchPoint(float x, float y, void *id) {
    for (int i = 0; i < 10; ++i) {
        if (g_touch_point[i].id == id) {
            g_touch_point[i].pt.x = x;
            g_touch_point[i].pt.y = y;
            g_touch_point[i].id = (void*)-1;
            break;
        }
    }
}

void updateTouchPoint(float x, float y, void *id) {
    for (int i = 0; i < 10; ++i) {
        if (g_touch_point[i].id == id) {
            g_touch_point[i].pt.x = x;
            g_touch_point[i].pt.y = y;
            break;
        }
    }
}

void routeTouchEvent(int msg) {
    
    if (msg == 1) {
        int index = 0;
        ufoPoint ptArr[10] = {0};
        for (int i = 0; i < 10; ++i) {
            if (g_touch_point[i].id == (void*)-1) {
                g_touch_point[i].id = 0;
                ptArr[index++] = g_touch_point[i].pt;
            }
        }
        internal_route_touchEvent(msg, ptArr, &index);
    }
    else {
        int index = 0;
        ufoPoint ptArr[10] = {0};
        for (int i = 0; i < 10; ++i) {
            if (g_touch_point[i].id) {
                ptArr[index++] = g_touch_point[i].pt;
            }
        }
        internal_route_touchEvent(msg, ptArr, &index);
    }
}

//MSG_TOUCH_DOWN,	0
//MSG_TOUCH_UP,		1
//MSG_TOUCH_CLICK,	2
//MSG_TOUCH_MOVE,	3

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    for (UITouch* touch in touches) {
        CGPoint point = [touch locationInView:self];
        point.x *= self.contentScaleFactor;
        point.y *= self.contentScaleFactor;
        
        addTouchPoint(point.x, point.y, touch);
    }
    routeTouchEvent(0);
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    for (UITouch* touch in touches) {
        CGPoint point = [touch locationInView:self];
        point.x *= self.contentScaleFactor;
        point.y *= self.contentScaleFactor;
        
        updateTouchPoint(point.x, point.y, touch);
    }
    routeTouchEvent(3);
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    for (UITouch* touch in touches) {
        CGPoint point = [touch locationInView:self];
        point.x *= self.contentScaleFactor;
        point.y *= self.contentScaleFactor;
        
        removeTouchPoint(point.x, point.y, touch);
    }
    routeTouchEvent(1);
}

- (void)myDrawFrame
{
    ufoRuningLoop(context);
}

-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    
}

- (void)layoutSubviews {
    
    [EAGLContext setCurrentContext:context];
    [self destroyFramebuffer];
    [self createFramebuffer];
	
    ufoRect rect = {0, 0, backingWidth, backingHeight};
    internal_route_sizeChanged(&rect, 0);
    [self drawView];
}

- (void)drawView {
    ufoRect rect2;
    ufoGetScreenRect(&rect2);
    ufoAddFreshRect(&rect2);
}

- (void)drawRect:(CGRect)rect {
    ufoRect rect2;
    ufoGetScreenRect(&rect2);
    ufoAddFreshRect(&rect2);
}

- (BOOL)createFramebuffer {
    self.contentScaleFactor = 2.0;
    CAEAGLLayer* eaglLayer = (CAEAGLLayer*)self.layer;
    eaglLayer.contentsScale = 2.0;
    
    glGenFramebuffersOES(1, &viewFramebuffer);
    glGenRenderbuffersOES(1, &viewRenderbuffer);
    
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [self.layer setOpaque:YES];
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];//### for what by yuedongweng
    
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
    
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
    
    glGenRenderbuffersOES(1, &depthRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
    glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH24_STENCIL8_OES, backingWidth, backingHeight);
    
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
    
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    
    if (0) {
        GLuint msaaFramebuffer_;
        GLuint msaaColorbuffer_;
        GLuint msaaDepthBuffer;
        GLint maxSamplesAllowed;
        glGetIntegerv(GL_MAX_SAMPLES_APPLE, &maxSamplesAllowed);
    
        glGenFramebuffers(1, &msaaFramebuffer_);
        glBindFramebuffer(GL_FRAMEBUFFER, msaaFramebuffer_);
    
        glGenRenderbuffers(1, &msaaColorbuffer_);
        glBindRenderbuffer(GL_RENDERBUFFER, msaaColorbuffer_);
    
        glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, maxSamplesAllowed, GL_RGBA8_OES , backingWidth, backingHeight);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaColorbuffer_);
        
        glGenRenderbuffersOES(1, &msaaDepthBuffer);   //Bind the msaa depth buffer.
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, msaaDepthBuffer);
        glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, 4, GL_DEPTH24_STENCIL8_OES, backingWidth , backingHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, msaaDepthBuffer);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, msaaDepthBuffer);       
        
        GLenum error;
        if ( (error=glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE)
        {
            NSLog(@"Failed to make complete framebuffer object 0x%X", error);
            return NO;
        }
    }
    
    return YES;
}

- (void)destroyFramebuffer {
    
    glDeleteFramebuffersOES(1, &viewFramebuffer);
    viewFramebuffer = 0;
    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
    viewRenderbuffer = 0;
    
    if(depthRenderbuffer) {
        glDeleteRenderbuffersOES(1, &depthRenderbuffer);
        depthRenderbuffer = 0;
    }
}

- (void)dealloc {
    
    if ([EAGLContext currentContext] == context) {
        [EAGLContext setCurrentContext:nil];
    }
    
    [context release];  
    [super dealloc];
}

- (void)exitApplication {

} 

- (void)animationFinished:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {  
	if ([animationID compare:@"exitApplication"] == 0) {  
//		exit(0);
	}
} 

- (void)registerForKeyboardNotifications
{
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardWillShowNotification object:nil];
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasHidden:) name:UIKeyboardWillHideNotification object:nil];
}

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
	//moveEGLViewOnKeyboardShow();
}
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
	//restoreEGLViewOnKeyboardHide();
}

@end
